﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MatchDetailsForm.cs" company="Roman '4ux-nbIx' Novitsky">
//   Copyright (c) Roman '4ux-nbIx' Novitsky 2010
// </copyright>
// <summary>
//   Defines the MatchDetailsForm type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace MtgMC
{
  #region Namespace Imports

  using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Linq;
  using System.Windows.Forms;

  using DataModel;

  #endregion


  /// <summary>
  /// Describes and manipulates the match details form.
  /// </summary>
  public partial class MatchDetailsForm : Form
  {
    #region Constants and Fields

    private readonly ApplicationData _applicationData;
    private readonly CustomGame _customGame;
    private bool _isInitializing = true;

    #endregion


    #region Constructors and Destructors

    /// <summary>
    /// Initializes a new instance of the <see cref="MatchDetailsForm"/> class.
    /// </summary>
    /// <param name="match">
    /// The match.
    /// </param>
    /// <param name="applicationData">
    /// The application data.
    /// </param>
    public MatchDetailsForm(Match match, ApplicationData applicationData)
    {
      _applicationData = applicationData;

      InitializeComponent();

      DialogResult = DialogResult.OK;
      Match = match ?? new Match();

      if (Match.Event is CustomGame)
      {
        _customGame = (CustomGame)Match.Event;
      }
      else
      {
        _customGame = new CustomGame { Name = "Custom Game" };
      }

      var gameEvents = new List<GameEvent> { _customGame };
      gameEvents.AddRange(_applicationData.Tournaments.Cast<GameEvent>());

      _eventComboBox.Initialize(gameEvents, "Name", Match.Event);
      _locationComboBox.Initialize(_applicationData.Locations, "Name", Match.Event != null ? Match.Event.Location : null);

      MatchType matchType = MatchType.OneOnOne;
      MatchFormat matchFormat = MatchFormat.Standard;

      if (Match.Event != null)
      {
        matchType = Match.Event.MatchType;
        matchFormat = Match.Event.MatchFormat;
      }

      _matchTypeComboBox.DataSource = MatchTypeExtensions.ValuesList;
      _matchTypeComboBox.SelectedItem = matchType;

      _matchFormatComboBox.DataSource = MatchFormatExtensions.ValuesList;
      _matchFormatComboBox.SelectedItem = matchFormat;

      _opponentComboBox.Initialize(_applicationData.Players, "Name", Match.Opponent);

      UpdateSelectedDecks();

      _isInitializing = false;
    }

    #endregion


    #region Properties

    /// <summary>
    /// Gets the match.
    /// </summary>
    /// <value>
    /// The match.
    /// </value>
    public Match Match
    {
      get;
      private set;
    }

    private bool IsTournamentSelected
    {
      get
      {
        return _applicationData.Tournaments.Contains(SelectedGameEvent as Tournament);
      }
    }

    private GameEvent SelectedGameEvent
    {
      get
      {
        return (GameEvent)_eventComboBox.SelectedItem;
      }
    }

    private MatchFormat SelectedMatchFormat
    {
      get
      {
        return (MatchFormat)_matchFormatComboBox.SelectedItem;
      }
    }

    private Player SelectedOpponent
    {
      get
      {
        if (_opponentComboBox.SelectedIndex >= 0)
        {
          return (Player)_opponentComboBox.SelectedItem;
        }

        return null;
      }
    }

    #endregion


    #region Methods

    /// <summary>
    /// Raises the <see cref="E:System.Windows.Forms.Form.Closing"/> event.
    /// </summary>
    /// <param name="e">
    /// A <see cref="T:System.ComponentModel.CancelEventArgs"/> that contains the event data.
    /// </param>
    protected override void OnClosing(CancelEventArgs e)
    {
      if (DialogResult == DialogResult.Cancel)
      {
        return;
      }

      GameEvent gameEvent = GetGameEvent();

      if (gameEvent == null)
      {
        e.Cancel = true;
        return;
      }

      Player opponent = GetOpponent();

      if (opponent == null)
      {
        e.Cancel = true;
        return;
      }

      Deck opponentDeck = GetDeck(gameEvent, _opponentDeckComboBox, "opponent's deck");

      if (opponentDeck == null)
      {
        e.Cancel = true;
        return;
      }

      Match.Event = gameEvent;
      Match.Opponent = opponent;
      Match.OpponentDeck = opponentDeck;
    }


    private static Deck GetDeck(GameEvent gameEvent, ComboBox deckComboBox, string deckMessageName)
    {
      Func<string, Deck> createDeckFunction = name => new Deck { Name = name, Format = gameEvent.MatchFormat, };

      Deck deck = deckComboBox.GetItem(deckMessageName, d => d.Name, createDeckFunction);

      return deck;
    }


    private void CancelMenuItemClick(object sender, EventArgs e)
    {
      DialogResult = DialogResult.Cancel;
    }


    private void DeckComboBoxSelectedIndexChanged(object sender, EventArgs e)
    {
      _customGame.Deck = (Deck)_deckComboBox.SelectedItem;
    }


    private void EventComboBoxSelectedIndexChanged(object sender, EventArgs e)
    {
      if (_isInitializing)
      {
        return;
      }

      _deckComboBox.Enabled = !IsTournamentSelected;
      _locationComboBox.Enabled = !IsTournamentSelected;
      _matchFormatComboBox.Enabled = !IsTournamentSelected;
      _matchTypeComboBox.Enabled = !IsTournamentSelected;

      _deckComboBox.SelectedItem = SelectedGameEvent.Deck;
      DeckComboBoxSelectedIndexChanged(this, EventArgs.Empty);

      _locationComboBox.SelectedItem = SelectedGameEvent.Location;
      LocationComboBoxSelectedIndexChanged(this, EventArgs.Empty);

      _matchTypeComboBox.SelectedItem = SelectedGameEvent.MatchType;
      MatchTypeComboBoxSelectedIndexChanged(this, EventArgs.Empty);

      _matchFormatComboBox.SelectedItem = SelectedGameEvent.MatchFormat;
      MatchFormatComboBoxSelectedIndexChanged(this, EventArgs.Empty);
    }


    private GameEvent GetGameEvent()
    {
      var gameEvent = _eventComboBox.GetItem<GameEvent>("event", e => e.Name, name => new Tournament { Name = name });

      if (gameEvent == null)
      {
        return null;
      }

      if (!_applicationData.Tournaments.Contains(gameEvent as Tournament))
      {
        Location location = _locationComboBox.GetItem("location", l => l.Name, name => new Location { Name = name });

        if (location == null)
        {
          return null;
        }

        Deck deck = GetDeck(gameEvent, _deckComboBox, "deck");

        if (deck == null)
        {
          return null;
        }

        gameEvent.MatchFormat = (MatchFormat)_matchFormatComboBox.SelectedItem;
        gameEvent.MatchType = (MatchType)_matchTypeComboBox.SelectedItem;
        gameEvent.Location = location;
        gameEvent.Deck = deck;
      }

      return gameEvent;
    }


    private Player GetOpponent()
    {
      return _opponentComboBox.GetItem("opponent", e => e.Name, name => new Player { Name = name });
    }


    private void InputPanelEnabledChanged(object sender, EventArgs e)
    {
      if (_inputPanel.Enabled)
      {
        _matchDetailsTabs.Height -= _inputPanel.Bounds.Height;
      }
      else
      {
        _matchDetailsTabs.Height += _inputPanel.Bounds.Height;
      }
    }


    private void LocationComboBoxSelectedIndexChanged(object sender, EventArgs e)
    {
      _customGame.Location = (Location)_locationComboBox.SelectedItem;
    }


    private void MatchFormatComboBoxSelectedIndexChanged(object sender, EventArgs e)
    {
      _customGame.MatchFormat = SelectedMatchFormat;

      bool isLimitedFormat = SelectedMatchFormat.IsLimitedFormat() && SelectedGameEvent != _customGame;

      _deckComboBox.Enabled = !isLimitedFormat;
      _opponentDeckComboBox.Enabled = !isLimitedFormat;

      UpdateSelectedDecks();
    }


    private void MatchTypeComboBoxSelectedIndexChanged(object sender, EventArgs e)
    {
      _customGame.MatchType = (MatchType)_matchTypeComboBox.SelectedItem;
    }


    private void OpponentComboBoxSelectedIndexChanged(object sender, EventArgs e)
    {
      UpdateOpponentDeckComboBox();
    }


    private void OpponentComboBoxTextChanged(object sender, EventArgs e)
    {
      UpdateOpponentDeckComboBox();
    }


    private void UpdateOpponentDeckComboBox()
    {
      var decks = new List<Deck>();
      Deck selectedDeck = null;

      var selectedTournament = SelectedGameEvent as Tournament;
      _opponentDeckComboBox.Enabled = true;

      if (selectedTournament != null)
      {
        TournamentOpponentInfo opponentInfo =
          selectedTournament.Opponents.Where(info => info.Opponent == SelectedOpponent).FirstOrDefault();

        if (opponentInfo != null && opponentInfo.Deck.Format == SelectedMatchFormat)
        {
          selectedDeck = opponentInfo.Deck;
          decks.Add(selectedDeck);

          _opponentDeckComboBox.Enabled = false;
        }

        if (selectedDeck == null && SelectedMatchFormat.IsLimitedFormat())
        {
          _opponentDeckComboBox.Text = selectedTournament.LimitedDeckName;
          _opponentDeckComboBox.Enabled = false;

          return;
        }
      }

      if (SelectedOpponent != null)
      {
        decks.AddRange(SelectedOpponent.Decks.Where(d => d.Format == SelectedMatchFormat));

        foreach (Tournament tournament in _applicationData.Tournaments)
        {
          if (tournament.MatchFormat != SelectedMatchFormat)
          {
            continue;
          }

          TournamentOpponentInfo opponentInfo =
            tournament.Opponents.Where(info => info.Opponent == SelectedOpponent).FirstOrDefault();

          if (opponentInfo != null && !decks.Contains(opponentInfo.Deck))
          {
            decks.Add(opponentInfo.Deck);
          }
        }
      }

      _opponentDeckComboBox.Initialize(decks, "Name", selectedDeck);
    }


    private void UpdatePlayerDeckComboBox()
    {
      var decks = new List<Deck>();
      Deck selectedDeck = null;

      var selectedTournament = SelectedGameEvent as Tournament;
      _deckComboBox.Enabled = true;

      if (selectedTournament != null)
      {
        if (selectedTournament.Deck.Format == SelectedMatchFormat)
        {
          selectedDeck = selectedTournament.Deck;
          decks.Add(selectedDeck);
          _deckComboBox.Enabled = false;
        }

        if (selectedDeck == null && SelectedMatchFormat.IsLimitedFormat())
        {
          _deckComboBox.Text = selectedTournament.LimitedDeckName;
          _deckComboBox.Enabled = false;
        }
      }

      decks.AddRange(_applicationData.Player.Decks.Where(d => d.Format == SelectedMatchFormat));

      foreach (Tournament tournament in _applicationData.Tournaments)
      {
        if (tournament.MatchFormat != SelectedMatchFormat)
        {
          continue;
        }

        if (!decks.Contains(tournament.Deck))
        {
          decks.Add(tournament.Deck);
        }
      }

      _deckComboBox.Initialize(decks, "Name", selectedDeck);
    }


    private void UpdateSelectedDecks()
    {
      UpdateOpponentDeckComboBox();
      UpdatePlayerDeckComboBox();
    }

    #endregion
  }
}